package com.px.auth.security;

import com.px.auth.config.ApiSecurityConfig;
import com.px.auth.util.TokenUtil;
import com.px.common.core.RespCode;
import com.px.common.core.RespException;
import com.px.common.util.JsonUtil;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.MacSigner;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class TokenAuthenticationFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader(ApiSecurityConfig.HEADER);
        try {
            Map claims = TokenUtil.getClaims(token);
            long exp = Long.valueOf((String) claims.get("exp"));
            if (exp - new Date().getTime() / 1000 < TimeUnit.DAYS.toSeconds(1)) {
                claims.put("exp", String.valueOf(new Date().getTime() / 1000 + TimeUnit.DAYS.toSeconds(2)));
                token = JwtHelper.encode(
                        JsonUtil.toJson(claims), new MacSigner(ApiSecurityConfig.JWT_SIGNER_STR)).getEncoded();
            }
        } catch (Exception e) {
            throw new RespException(RespCode.TOKEN_ERROR, null);
        }
        response.setHeader(ApiSecurityConfig.HEADER, token);

        Authentication auth = new TokenAuthentication(token);
        SecurityContextHolder.getContext().setAuthentication(auth);
        request.setAttribute("TokenAuthenticationFilter.FILTERED", true);
        filterChain.doFilter(request, response);
    }

    class TokenAuthentication implements Authentication {
        private String token;

        private TokenAuthentication(String token) {
            this.token = token;
        }

        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return null;
        }

        @Override
        public Object getCredentials() {
            return token;
        }

        @Override
        public Object getDetails() {
            return null;
        }

        @Override
        public Object getPrincipal() {
            return null;
        }

        @Override
        public boolean isAuthenticated() {
            return false;
        }

        @Override
        public void setAuthenticated(boolean authenticated) throws IllegalArgumentException {
        }

        @Override
        public String getName() {
            return "token";
        }
    }
}
